
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
// #include <arpa/inet.h>
// #include <sys/socket.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#include <time.h>

#pragma comment(lib, "ws2_32.lib") // 链接ws2_32库
#pragma comment(lib, "iphlpapi.lib")  // IP Helper Library

#define DEVICE_PORT             (60000)             //  设备的端口
#define SERVER_PORT             (DEVICE_PORT-1)     //  服务器端口

#define BUFFER_SIZE             2048

#define SYNC_CODE_1             (0xEB)
#define SYNC_CODE_2             (0x90)
#define TAIL_CODE               (0xAA)

#define CENTER_MSG_TRANS        (0x01)
#define CENTER_CODE_FILE_TRANS  (0x81)

#pragma pack(push, 1)
typedef struct
{
	uint8_t op_type;
	uint8_t uuid[40];
	uint8_t ip[4];
    uint8_t port[2];
    uint8_t fm_type;
} scanf_device_t;
#pragma pack(pop)


SOCKET serverSocket;
struct sockaddr_in serverAddr, clientAddr;
int clientAddrLen;
uint8_t g_recvbuf[BUFFER_SIZE];
uint8_t g_sendbuf[BUFFER_SIZE];
static int g_send_len;
FILE *g_cur_file;
uint32_t g_file_size = 0;

struct sockaddr_in broadcast_addr;


// 定义发送UDP广播数据的函数
void send_udp_broadcast(int sockfd, struct sockaddr_in *broadcast_addr, char *data) {
    int len = sendto(sockfd, data, strlen(data), 0, (struct sockaddr *)broadcast_addr, sizeof(struct sockaddr_in));
    if (len < 0) {
        perror("sendto");
        exit(EXIT_FAILURE);
    }
    printf("Broadcast data sent: %s\n", data);
}


/**************
 * 矿灯扫描工具 扫描 用到的码值， 所处的网络是：192.168.43.68（0xC0, 0xA8, 0x2b，0x44）
 * 		eb 90 01 00 00 00   +.._.`.@........
0030   30 11 64 61 33 30 30 36 66 37 2d 35 39 36 64 2d   0.da3006f7-596d-
0040   34 65 39 39 2d 39 33 38 37 2d 37 33 34 35 62 62   4e99-9387-7345bb
0050   35 61 32 33 39 36 00 00 00 00 c0 a8 2b 44 cd cd   5a2396......+D..
0060   01 aa                                             ..

 *
*/
void center_scanf_device(int sockfd, struct sockaddr_in *broadcast_addr)
{
    uint8_t len = 0,uid_len = 0;
    scanf_device_t scanf_data;
    g_send_len = 0x30;

    g_sendbuf[len++] = SYNC_CODE_1;
    g_sendbuf[len++] = SYNC_CODE_2;
    g_sendbuf[len++] = 0x01;    // 信息交互【code】
    g_sendbuf[len++] = 0x00;    // card_num_h
    g_sendbuf[len++] = 0x00;    // card_num_l

    g_sendbuf[len++] = 0x00;    // len_h
    g_sendbuf[len++] = 0x30;    // len_l

    scanf_data.op_type = 0x11;
    g_sendbuf[len++] = scanf_data.op_type; //

    scanf_data.uuid[uid_len++] = 0x64; scanf_data.uuid[uid_len++] = 0x61; scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x30;
    scanf_data.uuid[uid_len++] = 0x30; scanf_data.uuid[uid_len++] = 0x36; scanf_data.uuid[uid_len++] = 0x66; scanf_data.uuid[uid_len++] = 0x37;
    scanf_data.uuid[uid_len++] = 0x2d; scanf_data.uuid[uid_len++] = 0x35; scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x36;
    scanf_data.uuid[uid_len++] = 0x64; scanf_data.uuid[uid_len++] = 0x2d; scanf_data.uuid[uid_len++] = 0x34; scanf_data.uuid[uid_len++] = 0x65;
    scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x2d; scanf_data.uuid[uid_len++] = 0x39;

    scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x38; scanf_data.uuid[uid_len++] = 0x37; scanf_data.uuid[uid_len++] = 0x2d;
    scanf_data.uuid[uid_len++] = 0x37; scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x34; scanf_data.uuid[uid_len++] = 0x35;
    scanf_data.uuid[uid_len++] = 0x62; scanf_data.uuid[uid_len++] = 0x62; scanf_data.uuid[uid_len++] = 0x35; scanf_data.uuid[uid_len++] = 0x61;
    scanf_data.uuid[uid_len++] = 0x32; scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x36;
    scanf_data.uuid[uid_len++] = 0x00; scanf_data.uuid[uid_len++] = 0x00; scanf_data.uuid[uid_len++] = 0x00; scanf_data.uuid[uid_len++] = 0x00;

    memcpy(&g_sendbuf[len], scanf_data.uuid, uid_len);
    len += uid_len;

    len += 6;
    g_sendbuf[len++] = TAIL_CODE; //

    int send_len = sendto(sockfd, g_sendbuf, len, 0, (struct sockaddr *)broadcast_addr, sizeof(struct sockaddr_in));
    // int send_len = sendto(serverSocket, g_sendbuf, len, 0, (struct sockaddr *)&clientAddr, clientAddrLen);
    if (send_len < 0) {
        perror("sendto");
        exit(EXIT_FAILURE);
    }
    printf("Broadcast data sent \n" );

}
/*************************************
 * len = 1(cmd) + 40(uuid)+ 1(code_num) + 64(resver) = 106 = 0x6A
  * 矿灯扫描工具 扫描 用到的码值， 所处的网络是：192.168.43.68（0xC0, 0xA8, 0x2b，0x44）
 * 		eb 90 01 00 00 00   +.._.`.@........
0030   6A 
          0b 
             64 61 33 30 30 36 66 37 2d 35 39 36 64 2d   0.da3006f7-596d-
0040   34 65 39 39 2d 39 33 38 37 2d 37 33 34 35 62 62   4e99-9387-7345bb
0050   35 61 32 33 39 36 00 00 00 00 
                                     c0 a8 2b 44 cd cd   5a2396......+D..
0060   01 aa    
******************************/
void center_ctrl_device(int code_num)
{
    uint8_t len = 0,uid_len = 0;
    scanf_device_t scanf_data;
    g_send_len = 0x30;

    g_sendbuf[len++] = SYNC_CODE_1;
    g_sendbuf[len++] = SYNC_CODE_2;
    g_sendbuf[len++] = 0x01;    // 信息交互【code】
    g_sendbuf[len++] = 0x00;    // card_num_h
    g_sendbuf[len++] = 0x00;    // card_num_l

    g_sendbuf[len++] = 0x00;    // len_h
    g_sendbuf[len++] = 0x6a;    // len_l

    scanf_data.op_type = 0x0b;
    g_sendbuf[len++] = scanf_data.op_type; //

    scanf_data.uuid[uid_len++] = 0x64; scanf_data.uuid[uid_len++] = 0x61; scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x30;
    scanf_data.uuid[uid_len++] = 0x30; scanf_data.uuid[uid_len++] = 0x36; scanf_data.uuid[uid_len++] = 0x66; scanf_data.uuid[uid_len++] = 0x37;
    scanf_data.uuid[uid_len++] = 0x2d; scanf_data.uuid[uid_len++] = 0x35; scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x36;
    scanf_data.uuid[uid_len++] = 0x64; scanf_data.uuid[uid_len++] = 0x2d; scanf_data.uuid[uid_len++] = 0x34; scanf_data.uuid[uid_len++] = 0x65;
    scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x2d; scanf_data.uuid[uid_len++] = 0x39;

    scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x38; scanf_data.uuid[uid_len++] = 0x37; scanf_data.uuid[uid_len++] = 0x2d;
    scanf_data.uuid[uid_len++] = 0x37; scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x34; scanf_data.uuid[uid_len++] = 0x35;
    scanf_data.uuid[uid_len++] = 0x62; scanf_data.uuid[uid_len++] = 0x62; scanf_data.uuid[uid_len++] = 0x35; scanf_data.uuid[uid_len++] = 0x61;
    scanf_data.uuid[uid_len++] = 0x32; scanf_data.uuid[uid_len++] = 0x33; scanf_data.uuid[uid_len++] = 0x39; scanf_data.uuid[uid_len++] = 0x36;
    scanf_data.uuid[uid_len++] = 0x00; scanf_data.uuid[uid_len++] = 0x00; scanf_data.uuid[uid_len++] = 0x00; scanf_data.uuid[uid_len++] = 0x00;

    memcpy(&g_sendbuf[len], scanf_data.uuid, uid_len);
    len += uid_len;
    g_sendbuf[len++] = code_num;
    len += 64;
    g_sendbuf[len++] = TAIL_CODE; //

    // int send_len = sendto(sockfd, g_sendbuf, len, 0, (struct sockaddr *)broadcast_addr, sizeof(struct sockaddr_in));
    int send_len = sendto(serverSocket, g_sendbuf, len, 0, (struct sockaddr *)&clientAddr, clientAddrLen);
    if (send_len < 0) {
        perror("sendto");
        exit(EXIT_FAILURE);
    }
    printf("Broadcast send code:%d, len:%d, succ_len:%d \n",code_num, len, send_len);

}


/*********************************************
 * // 线程1函数, 按键处理任务
 * 
*********************************************/

DWORD WINAPI get_keyboard_ThreadFunction(LPVOID lpParam) {
    char ch;
    int threadID = *(int*)lpParam; // 获取线程参数

    printf("线程 %d 正在运行\n", threadID);
    while(1){
        ch = getchar();
        switch(ch){
            case '0':
                printf("get_ '0' \r\n");
                ch = 'q';
                break;

            case '1':
                printf("get_ '1' \r\n");
                center_ctrl_device(1);
                ch = 'q';
                 break;
            case '2':
                printf("get_ '2' \r\n");
                center_ctrl_device(2);
                ch = 'q';
                break;
            case '3':
                printf("get_ '3' \r\n");
                center_ctrl_device(3);
                ch = 'q';
                break;
            case '4':
                printf("get_ '4' \r\n");
                center_ctrl_device(4);
                ch = 'q';
                break;
            default:
                break;
        }
        Sleep(100); // 模拟线程工作，休眠100ms
    }
    
    printf("线程 %d 已完成\n", threadID);
    //return 0; // 线程返回值
}

/*********************************************
 * // 线程2函数, 监听任务
 * 
*********************************************/

DWORD WINAPI listen_dev_ack_ThreadFunction(LPVOID lpParam) {
    char ch;
    int threadID = *(int*)lpParam; // 获取线程参数

    clientAddr;
    clientAddrLen = sizeof(clientAddr);

    printf("listen_dev_ack_ThreadFunction run\n", threadID);
    while(1){
        int bytesReceived = recvfrom(serverSocket, g_recvbuf, BUFFER_SIZE, 0, (struct sockaddr*)&clientAddr, &clientAddrLen);
        if (bytesReceived == SOCKET_ERROR) {
            printf("recvfrom failed with error: %d\n", WSAGetLastError());
            break;
        }
        g_recvbuf[bytesReceived] = '\0'; // Null-terminate the string
        // printf("Received from client: %02x %02x %02x %02x len:%d\n", g_recvbuf[0], g_recvbuf[1], g_recvbuf[2], g_recvbuf[3], bytesReceived);
        printf("Received reply from %s:%d - %s\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port), g_recvbuf);
        if((g_recvbuf[0] == 0xEB) && (g_recvbuf[1] == 0x90) && g_recvbuf[2] == 0x81) {
            // file_trans_handler();
        }
        Sleep(100); // 模拟线程工作，休眠100ms
    }
    
    printf("线程 %d 已完成\n", threadID);
    //return 0; // 线程返回值
}


//******************************************************
//  编译方法：
//      gcc main.c -o a.exe  -lws2_32 -liphlpapi
//
//******************************************************
int main() {

    WSADATA wsa;
    struct addrinfo hints, *res;
    char hostname[256];
    char ipstr[INET6_ADDRSTRLEN];
    int status;
    unsigned char *octets;
  
    HANDLE threads[2]; // 用于存储线程句柄
    int threadIDs[2] = {1, 2}; // 线程参数
    DWORD threadID; // 用于存储线程ID

    printf("main step1 \n");    
    // WINDOWS 下必须用到的初始化
    int wsOk = WSAStartup(MAKEWORD(2, 2), &wsa);
    if (wsOk != 0) {
        printf("Can't Initialize winsock! %d\n", wsOk);
        return -1;
    }

    // 创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        perror("socket");
        while(1);
        exit(EXIT_FAILURE);
    }

    // 设置套接字选项，允许发送广播数据
    int broadcast_enable = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast_enable, sizeof(broadcast_enable)) < 0) {
        perror("setsockopt");
        close(sockfd);
        while(1);
        exit(EXIT_FAILURE);
    }

    serverSocket = sockfd;
    // 初始化本地地址
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    // 绑定本地端口
    if (bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
        perror("bind server failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }


   // 获取本机主机名
    if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) {
        printf("gethostname failed.\n");
        WSACleanup();
        return 1;
    }

    printf("Hostname: %s\n", hostname);
    // 获取本机地址
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET; // 仅获取IPv4地址
    hints.ai_socktype = SOCK_STREAM;

      // 获取主机地址信息
    if ((status = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
        printf("getaddrinfo failed: %d\n", status);
        WSACleanup();
        return 1;
    }

    // 遍历结果，获取第一个IPv4地址
    struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
    inet_ntop(AF_INET, &(ipv4->sin_addr), ipstr, INET_ADDRSTRLEN);
    printf("Local IPv4 address: %s\n", ipstr);

    struct sockaddr_in boardcast_ipv4;
    memcpy(&boardcast_ipv4, ipv4,sizeof(boardcast_ipv4));
    // 修改最后一个字段为 255
    octets = (unsigned char *)&boardcast_ipv4.sin_addr;
    octets[3] = 255;

    // 定义广播地址
    struct sockaddr_in broadcast_addr;
    memset(&broadcast_addr, 0, sizeof(broadcast_addr));
    broadcast_addr.sin_family = AF_INET;
    broadcast_addr.sin_port = htons(DEVICE_PORT); // 广播端口(目标端口)
    // broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // 广播地址
    memcpy(&broadcast_addr.sin_addr, &boardcast_ipv4.sin_addr,sizeof(boardcast_ipv4.sin_addr));
    // broadcast_addr.sin_addr.s_addr = boardcast_ipv4.sin_addr; // 广播地址

    // 定义要发送的数据
    char data[] = "Hello, UDP Broadcast! 001 007 008";

    threads[0] = CreateThread(
        NULL, // 安全属性，NULL表示默认安全属性
        0,    // 堆栈大小，0表示默认大小
        get_keyboard_ThreadFunction, // 线程函数
        &threadIDs[0], // 传递给线程的参数
        0,    // 创建标志，0表示立即运行
        &threadID // 存储线程ID
    );

    if (threads[0] == NULL) {
        printf("创建线程 %d 失败，错误码：%d\n",  1, GetLastError());
        return 1;
    }

    threads[1] = CreateThread(
        NULL, // 安全属性，NULL表示默认安全属性
        0,    // 堆栈大小，0表示默认大小
        listen_dev_ack_ThreadFunction, // 线程函数
        &threadIDs[1], // 传递给线程的参数
        0,    // 创建标志，0表示立即运行
        &threadID // 存储线程ID
    );

    if (threads[1] == NULL) {
        printf("创建线程 %d 失败，错误码：%d\n",  2, GetLastError());
        return 1;
    }

    // 设置定时发送间隔（单位：秒）
    int interval = 10;

     // 获取当前时间
    time_t start_time = time(NULL);
    while (1) {
         // 获取当前时间
         time_t current_time = time(NULL);
        // 计算时间差
        if (difftime(current_time, start_time) >= interval) {
            // 发送UDP广播数据
            // send_udp_broadcast(sockfd, &broadcast_addr, data);
            // printf("scanf **** \n");
            printf("enter: [1]=reboot,  [2]=picture, [3]=rec_voice, [4]=rec_video \n");
            center_scanf_device(sockfd, &broadcast_addr);
            // center_scanf_device();
            // 更新开始时间
            start_time = current_time;
        }
        // 短暂休眠，避免CPU占用过高
        Sleep(200); // 休眠200毫秒
    }

    // 关闭套接字
    close(sockfd);
}
